package com.example.core.filter.loadbalance.impl;

import com.example.common.config.DynamicConfigManager;
import com.example.common.config.ServiceInstance;
import com.example.common.exception.NotFoundException;
import com.example.core.context.GatewayContext;
import com.example.core.filter.loadbalance.ILoadBalanceRule;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;

import static com.example.common.enums.ResponseCode.SERVICE_INSTANCE_NOT_FOUND;

/**
 * @Author Peng Yisheng
 * @Date 2024/12/3 15:20
 * @Description 随机 负载均衡算法
 */
@Slf4j
public class RandomLoadBalanceRule implements ILoadBalanceRule {

    private final String serviceId;

    public RandomLoadBalanceRule(String serviceId) {
        this.serviceId = serviceId;
    }

    private static ConcurrentHashMap<String, RandomLoadBalanceRule> serviceMap = new ConcurrentHashMap<>();

    public static RandomLoadBalanceRule getInstance(String serviceId) {
        RandomLoadBalanceRule loadBalanceRule = serviceMap.get(serviceId);
        if (loadBalanceRule == null) {
            loadBalanceRule = new RandomLoadBalanceRule(serviceId);
            serviceMap.put(serviceId, loadBalanceRule);
        }
        return loadBalanceRule;
    }

    @Override
    public ServiceInstance choose(GatewayContext ctx) {
        String serviceId = ctx.getUniqueId();
        return choose(serviceId, ctx.isGray());
    }

    @Override
    public ServiceInstance choose(String serviceId, boolean gray) {
        Set<ServiceInstance> serviceInstanceSet = DynamicConfigManager.getInstance().getServiceInstanceByUniqueId(serviceId, gray);
        if (serviceInstanceSet.isEmpty()) {
            log.warn("No instance available for:{}", serviceId);
            throw new NotFoundException(SERVICE_INSTANCE_NOT_FOUND);
        }
        // TODO: 能不能不构建新的List？
        List<ServiceInstance> instances = new ArrayList<>(serviceInstanceSet);
        // ThreadLocalRandom 的随机是均匀随机
        int index = ThreadLocalRandom.current().nextInt(instances.size());
        ServiceInstance instance = (ServiceInstance) instances.get(index);
        return instance;
    }
}
